/*!
 * @file ble_xfer_lpuart.c
 * @author suyong_yq@126.com
 */

#include "hal_edma.h"
#include "hal_dmamux.h"
#include "drv_lpuart_edma.h"
#include "ble_xfer_lpuart.h"

#include "bsp_config.h"

#include "rbuf.h"
#include <stdio.h>
#include <stdarg.h>

/* 本组件还将维护同上位机同步数据的功能：
* 使用一个定时器，周期向BLE模块发送包含状态信息的字符串，同步显示在手机App的界面上
*/

/* 发送部分 */
LPUART_EDMA_TxHandler_T bleLpuartEdmaTxHandlerStruct;   /* 发送操作句柄 */
LPUART_EDMA_TxHwDev_T   bleLpuartEdmaTxHwDevStruct = {
    .LpuartBase                 = LPUART1,
    .enReConfigLpuart           = true, /* 在初始化EDMA发送过程中配置好LPUART */
    .EdmaLpuartTxChnIdx         = 2U, /* 使用DMA2通道 */
    .EdmaLpuartTxTriggerSource  = eDMAMUX_TriggerSource_LPUART1_Tx,
    .EdmaTxChnIRQn              = DMA2_IRQn /* DMA2的中断向量号 */
};
LPUART_Config_T         bleLpuartConfigStruct = {
    .BusClkHz = BSP_CLK_SPLLDIV2_HZ,
    .Baudrate = 115200U
};
char bleLpuartPrintfBuf[50]; /* 格式化打印的缓冲区 */

/* 接收部分 */
#define                 APP_BLE_LPUART_INT_RX_BUF_LEN  20U
uint8_t                 bleLpuartIntRxBuf[APP_BLE_LPUART_INT_RX_BUF_LEN];
RBUF_Handler_T          bleLpuartIntRxBufHandlerStruct; /* 接收缓冲区结构体 */
struct
{
    uint8_t PreCmd; /* 前一次接收的命令字 */
} bleLpuartIntRxHandlerStruct;



/* 使用LPUART1与BLE透传模块通信
* 1. 发送使用eDMA自动传输
* 2. 接收使用中断方式捕获，对接收数据进行预处理后存入队列，在应用主循环中解析命令并分发消息
*/
void BleXfer_Init(void)
{
    BSP_InitLpuartForBLE();

    /* 初始化发送部分，EDMA方式 */
    LPUART_EDMA_InitTxHw(&bleLpuartEdmaTxHandlerStruct,
                         &bleLpuartEdmaTxHwDevStruct,
                         &bleLpuartConfigStruct);

    /* 初始化接收部分，中断方式 */
    /* 初始化数据结构 */
    bleLpuartIntRxHandlerStruct.PreCmd = 0U;
    RBUF_Init(&bleLpuartIntRxBufHandlerStruct, bleLpuartIntRxBuf, APP_BLE_LPUART_INT_RX_BUF_LEN);

    LPUART_HAL_EnableInterrupts(LPUART1, LPUART_HAL_INT_RX_FULL_MASK, true);
    NVIC_EnableIRQ(LPUART1_RX_IRQn);
    LPUART_HAL_EnableRx(LPUART1, true);
}

/* 利用EDMA自动搬运数据倒LPUART通信引擎的发送功能函数
* 1. 仅仅触发发送过程
* 2. 发送完成后调用回调函数
*/
void BleXfer_Send(uint8_t *bufPtr, uint32_t bufLen, void (*txDoneCallback)(void))
{
    LPUART_EDMA_StartTx(&bleLpuartEdmaTxHandlerStruct, bufPtr, bufLen, txDoneCallback);
}

#if 0
void BleXfer_Printf(const char *format, ...)
{
    va_list argp;

    /* 传递变长参数到sprintf函数中 */
    va_start(argp, format); /* 将可变长参数转换为va_list */
    sprintf(bleLpuartPrintfBuf, format, argp); /* 使用argp作为变长参数 */
    va_end(argp);

    BleXfer_Send((uint8_t *)bleLpuartPrintfBuf, strlen(bleLpuartPrintfBuf), NULL);
}
#endif

/* 在LPUART接收中断服务程序中调用本函数：
* 1. 处理冗余数据
* 2. 填充有效命令字到命令队列
*/
void BleXfer_FeedDataIntoCmdFifo(uint8_t ch)
{
    if (ch == bleLpuartIntRxHandlerStruct.PreCmd)
    {
        return; /* 同前一命令相同，即保持现状 */
    }

    /* 将新命令压入命令队列 */
    if (!RBUF_IsFull(&bleLpuartIntRxBufHandlerStruct))
    {
        RBUF_PutDataIn(&bleLpuartIntRxBufHandlerStruct, ch);
        bleLpuartIntRxHandlerStruct.PreCmd = ch; /* 保留最近接收的命令字，供滤波器使用 */
    }
}

/* 获取命令码，在主循环中周期调用
* 1. 当命令队列为空时，返回0U
* 2. 当命令队列为非空时，一次只取最早进入队列的命令
*/
uint8_t BleXfer_GetRunCmdFromCmdFifo(void)
{
    if (RBUF_IsEmpty(&bleLpuartIntRxBufHandlerStruct))
    {
        return 0U;
    }
    return RBUF_GetDataOut(&bleLpuartIntRxBufHandlerStruct);
}

/* LPUART1接收中断服务程序入口 */
void LPUART1_RX_IRQHandler(void)
{
    if ( LPUART_HAL_FLAG_RX_FULL_MASK == (LPUART_HAL_FLAG_RX_FULL_MASK & LPUART_HAL_GetStatus(LPUART1)) )
    {
        BleXfer_FeedDataIntoCmdFifo(LPUART_HAL_GetRxData(LPUART1)); /* 向命令FIFO中喂数据 */
    }
}

/* LPUART1使用EDMA发送完成中断服务程序入口 */
void DMA2_IRQHandler(void)
{
    LPUART_EDMA_TxIRQHandler(&bleLpuartEdmaTxHandlerStruct);
}

/* EOF. */

